package com.dman.multi.core;

import java.io.EOFException;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

import com.dman.multi.proto.ProtocolHandler;
import com.dman.multi.proto.ProtocolHandlerFactory;
import com.dman.multi.proxy.ProxyAdaptor;
import com.dman.multi.proxy.ProxyDelegator;

public class Section implements Serializable, Callable<SocketChannel> {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private URL url;
	private String strUrl;
	private long startPos;
	private long currPos;
	private transient ProtocolHandler protoHandler = null;
	private Long size = 0l;
	private boolean closed;
	private boolean canResume = true;
	private ProxyAdaptor proxyAuth;
	private ProxyDelegator proxyDel;
	
	private static Map<String, ProxyAdaptor> urlProxy = new HashMap<String, ProxyAdaptor>();
	
	public Section(String url, long startPos) throws MalformedURLException{
		this(url, startPos, urlProxy.get(url));
	}

	public Section(String url, long startPos, ProxyAdaptor proxyAuth) throws MalformedURLException {
		strUrl = url;
		this.url = new URL(url);
		this.startPos = startPos;
		this.currPos = startPos;
		this.proxyAuth = (proxyAuth == null)?ProxyAdaptor.NO_PROXYAUTH:proxyAuth;
		urlProxy.put(strUrl, proxyAuth);
		proxyDel = ProxyDelegator.getInstance();
	}

	@Override
	public SocketChannel call() throws IOException {
		// initialize the factory and create protocol handler
		ProtocolHandlerFactory phf = ProtocolHandlerFactory.getInstance();
		String proto = proxyDel.identifyProtocol(url, proxyAuth);
		protoHandler = phf.getProtocolHandler(proto);
		
		// perform the other operations
		closed = false;
		currPos = (canResume)?currPos:startPos;
		Long seclen = protoHandler.init(url, currPos, proxyAuth);
		if(canResume && (seclen == null || seclen < 0))
			canResume = false;
		if(size != null && size == 0)
			size = seclen;
		return protoHandler.socketChannel();
	}
	
	public ByteBuffer read() throws EOFException, IOException{
		return protoHandler.read();
	}

	public Long getSize() {
		return size;
	}

	public long getStartPos() {
		return startPos;
	}

	public long getCurrPos() {
		return currPos;
	}
	
	public void close() throws IOException{
		protoHandler.close();
		closed = true;
	}
	
	public boolean isClosed() {
		return closed;
	}

	public String getStrUrl() {
		return strUrl;
	}

	public void setCurrPos(long currPos) {
		this.currPos = currPos;
	}
}
